package gin_encoder

import (
	"context"
	"errors"
	"github.com/gin-gonic/gin"
	"go.opentelemetry.io/otel/trace"
	"net/http"
	"time"
)

type Response struct {
	Data interface{} `json:"data"` // 响应的数据放在这里

	Code      int64  `json:"code"`      // 业务响应码
	Message   string `json:"message"`   // "操作成功"
	Status    bool   `json:"status"`    // true
	Timestamp int64  `json:"timestamp"` // 1655210662 秒级时间戳
	TraceId   string `json:"trace_id"`
}

func GetDefaultMiddlewareResult() *Response {
	return &Response{
		Code:      OK,
		Data:      nil,
		Timestamp: time.Now().Unix(),
		Status:    true,
		Message:   "操作成功",
	}
}

func GinResponseEncoderMiddleware(c *gin.Context) {
	v := GetDefaultMiddlewareResult()
	c.Set("result", v)
	span := trace.SpanContextFromContext(c.Request.Context())
	finish := make(chan struct{})
	go func() { // 子协程只会将返回数据写入到内存buff中
		c.Next()
		finish <- struct{}{}
	}()

	select {
	case <-finish:
		x, e := c.Get("result")
		if e {
			v, e = x.(*Response)
			if e {
				// 数据返回
				c.JSON(http.StatusOK, gin.H{
					"data":      v.Data,
					"code":      v.Code,
					"message":   v.Message,
					"status":    v.Status,
					"timestamp": v.Timestamp,
					"trace_id":  span.TraceID(),
				})
			}
		}
	}
	c.Header("Content-Type", "application/json")
}

func GetCtxAndResult(c *gin.Context) (ctx context.Context, span trace.Span, result *Response, err error) {
	x, ok := c.Get("result")
	if !ok {
		c.Abort()
		err = errors.New("useless result content")
		return
	}
	result, e := x.(*Response)
	if !e {
		c.Abort()
		err = errors.New("useless result content")
		return
	}
	ctx = c.Request.Context()
	span = trace.SpanFromContext(c.Request.Context())
	return
}
